package com.idroc.cdfs.service.meta;

import java.net.InetSocketAddress;
import java.util.TreeMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.idroc.rpc.RPCFactory;
import com.idroc.rpc.RPCService;

/**
 * 代理注册端点
 * @author 詹都林 (zhandl@hainan.net)  
 * Aug 13, 2009 4:18:10 PM
 * @memo:
 */
public class ProxyRegistryEndpoint implements RegistryEndpoint {
	
	private static final Logger log = LoggerFactory.getLogger(ProxyRegistryEndpoint.class);
	
	/**
	 * 远程端点编号
	 */
	private Integer remoteNo = null;
	
	/**
	 * 远程端点主机(IP or domain name)
	 */
	private String remoteHost = null;
	
	/**
	 * 远程端点端口
	 */
	private Integer remotePort = null; 
	
	private transient int hashCode = 0;
	
	/**
	 * 远程端点代理
	 */
	private transient RegistryEndpoint proxy = null;
	
	public ProxyRegistryEndpoint() {}
	
	public ProxyRegistryEndpoint(String host, Integer port) {
		
		this.remoteHost = host;
		this.remotePort = port;
		InetSocketAddress endpoint = new InetSocketAddress(remoteHost, remotePort);
		RPCService service = RPCFactory.getEndpoint(endpoint);
		proxy = service.toProxy(RegistryEndpoint.class); 
		this.remoteNo = proxy.getEndpointNo();
	}
	
	public ProxyRegistryEndpoint(RegistryEndpoint ep) {
		this(ep.getEndpointHost(), ep.getEndpointPort()); 
	}

	/*
	 * 
	 * @see com.idroc.cdfs.service.meta.RegistryEndpoint#addEndpoint(com.idroc.cdfs.service.meta.RegistryEndpoint, com.idroc.cdfs.service.meta.RegistryEndpoint)
	 */
	public boolean addEndpoint(RegistryEndpoint fromRoot,
			RegistryEndpoint newArrive) {
		
		try {
			log.debug("start call addEndpoint. fromRoot:{}, newArrive:{}", fromRoot, newArrive); 
			return proxy.addEndpoint(fromRoot, newArrive);
		} catch (Exception ex) {
			log.error("addEndpoint Exception", ex);
		}
		return false;
	}

	/*
	 * 
	 * @see com.idroc.cdfs.service.meta.RegistryEndpoint#checkAlive()
	 */
	public boolean checkAlive() {
		
		try { 
			log.debug("call checkAlive.");
			return proxy.checkAlive();
		} catch (Exception ex) {
			log.error("checkAlive Exception", ex);
		}
		return false;
	}

	/*
	 * 
	 * @see com.idroc.cdfs.service.meta.RegistryEndpoint#dropEndpoint(com.idroc.cdfs.service.meta.RegistryEndpoint, java.lang.Integer)
	 */
	public boolean dropEndpoint(RegistryEndpoint fromRoot, Integer epNo) {

		try { 
			log.debug("call dropEndpoint. fromRoot:{}, epNo:{}", fromRoot, epNo);
			return proxy.dropEndpoint(fromRoot, epNo);
		} catch (Exception ex) {
			log.error("dropEndpoint Exception", ex);
		}
		return false;
	}

	public String getEndpointHost() {

		return remoteHost;
	}

	public Integer getEndpointNo() {
		
		return remoteNo;
	}

	public Integer getEndpointPort() {

		return remotePort;
	}

	/*
	 * 
	 * @see com.idroc.cdfs.service.meta.RegistryEndpoint#getRegisteredEndpoint()
	 */
	public TreeMap<Integer, RegistryEndpoint> getRegisteredEndpoint() {

		try { 
			log.debug("call getRegisteredEndpoint");
			return proxy.getRegisteredEndpoint();
		} catch (Exception ex) {
			log.error("getRegisteredEndpoint Exception", ex);
		}
		return null;
	}

	/*
	 * 
	 * @see com.idroc.cdfs.service.meta.RegistryEndpoint#getRootEndpoint()
	 */
	public RegistryEndpoint getRootEndpoint() {
		try { 
			log.debug("call getRootEndpoint");
			return proxy.getRootEndpoint();
		} catch (Exception ex) {
			log.error("getRootEndpoint Exception", ex);
		}
		return null;
	}

	/*
	 * 
	 * @see com.idroc.cdfs.service.meta.RegistryEndpoint#rebuildRootEndpoint(boolean)
	 */
	public RegistryEndpoint rebuildRootEndpoint(boolean nested) {
		try { 
			log.debug("call rebuildRootEndpoint. nested:{}", nested);
			return proxy.rebuildRootEndpoint(nested);
		} catch (Exception ex) {
			log.error("rebuildRootEndpoint Exception", ex);
		}
		return null;
	}

	/*
	 * 
	 * @see com.idroc.cdfs.service.meta.RegistryEndpoint#registerEndpoint(com.idroc.cdfs.service.meta.RegistryEndpoint)
	 */
	public boolean registerEndpoint(RegistryEndpoint ep) {
		try { 
			log.debug("call registerEndpoint. ep:{}", ep);
			return proxy.registerEndpoint(ep);
		} catch (Exception ex) {
			log.error("registerEndpoint Exception", ex);
		}
		return false;
	}

	/*
	 * 
	 * @see com.idroc.cdfs.service.meta.RegistryEndpoint#replaceRootEndpoint(com.idroc.cdfs.service.meta.RegistryEndpoint)
	 */
	public boolean replaceRootEndpoint(RegistryEndpoint ep) {
		try { 
			log.debug("call replaceRootEndpoint. ep:{}", ep);
			return proxy.replaceRootEndpoint(ep);
		} catch (Exception ex) {
			log.error("replaceRootEndpoint Exception", ex);
		}
		return false;
	}

	/*
	 * 
	 * @see com.idroc.cdfs.service.meta.RegistryEndpoint#unregisterEndpoint(java.lang.Integer)
	 */
	public boolean unregisterEndpoint(Integer epNo) {
		try { 
			log.debug("call unregisterEndpoint. ep:{}", proxy);
			return proxy.unregisterEndpoint(epNo);
		} catch (Exception ex) {
			log.error("unregisterEndpoint Exception", ex);
		}
		return false;
	}

	
	/**
	 * 当 编号相同, 主机IP相同, 端口相同, 认为两个端点相同
	 */
	@Override
	public boolean equals(Object obj) { 
		
		if (null == obj) {
			return false;
		}
		if (obj instanceof RegistryEndpoint) {
			RegistryEndpoint ep = (RegistryEndpoint)obj;
			Integer no = ep.getEndpointNo();
			String host = ep.getEndpointHost();
			Integer port = ep.getEndpointPort();
			return remoteNo.equals(no) && this.remoteHost.equals(host) && this.remotePort.equals(port);
		} else {
			return false;
		}
	}

	@Override
	public int hashCode() { 
		
		if (hashCode == 0) {
			
			hashCode = 17;
			hashCode = 37 * hashCode + remoteNo.hashCode();
			hashCode = 37 * hashCode + remoteHost.hashCode();
			hashCode = 37 * hashCode + remotePort.hashCode();
		}
		return hashCode;
	}
	
	@Override
	public String toString() {
		
		StringBuilder sb = new StringBuilder();
		sb.append("ProxyRegistryEndpoint[");
		sb.append("remoteNo:").append(remoteNo).append(",");
		sb.append("remoteHost:").append(remoteHost).append(",");
		sb.append("remotePort:").append(remotePort);
		sb.append("]");
		return sb.toString();
	}
}
